#include <fstream>
#include <memory>
#include <vector>
#include <iterator>
#include <map>
#include "sample_header.hpp"

namespace SAMPLE_CODE
{

SampleClassHelper::SampleClassHelper(std::shared_ptr<DataS1> const & _inData1
                                    ,std::shared_ptr<DataS2> const & _inData2
                                    ,UINT32                  const   _cnt) noexcept
  : mCnt  { _cnt }
  , mData1 { _inData1 }
  , mData2 { _inData2 }
{ }

/* A12-1-3 */
// coverity[autosar_cpp14_a12_1_3_violation : FALSE]
// coverity[autosar_cpp14_a12_1_5_violation : FALSE]
SampleClass1::SampleClass1(std::shared_ptr<DataS1> const & _inData1
                          ,std::shared_ptr<DataS2> const & _inData2
                          ,UINT32                  const   _cnt) noexcept
  : INTERVAL { 100 }
  , mRun     { TRUE }
  , mCnt     { _cnt }
  , mSleepMutex { }
  , mSleepCV { }
  , mData1   { _inData1 }
  , mData2   { _inData2 }
  , mHelper  { std::make_shared<SampleClassHelper>(mData1, mData2, mCnt) } 
{ }

void SampleClass1::Start() noexcept
{
    static_cast<void>(std::endl(std::cout << "SampleClass1::Start"));
    UINT64 i {0U};
    while (mRun)
    {
        if (i >= mCnt) {
            break;
        }
        /* M5-0-4 */
        if (i < UINT64_MAX) {
            i += UINT64_1;
        }
        static_cast<void>(std::endl(std::cout << INTERVAL));

        std::unique_lock<std::mutex> lck { mSleepMutex };
        static_cast<void>(mSleepCV.wait_for(lck, std::chrono::milliseconds(INTERVAL), [this]() noexcept -> BOOL
        {
            return !mRun;
        }));
    }
}

bool sample_func_1(UINT64 const _input) noexcept {
    bool result {TRUE};
    /* A3-3-2 */
    // coverity[autosar_cpp14_a3_3_2_violation : FALSE]
    static UINT64 const the_first_constant_input { _input };
    /* M5-0-4 */
    if ((_input != UINT64_MAX) && (the_first_constant_input < (UINT64_MAX - _input))) {
        result = FALSE;
    }
    return result;
}

void sample_func_2(std::string const & _filename) noexcept {
    std::ofstream ofs {};
    /* A4-5-1 : http://www.cplusplus.com/reference/fstream/fstream/open/ */
    //coverity[autosar_cpp14_a4_5_1_violation : FALSE]
    ofs.open(_filename, std::ios::out|std::ios::trunc);
    ofs << "A4-5-1";
    ofs.close();
}

bool sample_func_3(std::map<INT32, std::string> const & _mapVal) noexcept {
    bool result {TRUE};
    std::map<INT32, std::string>::const_iterator it { _mapVal.begin() };
    while (it != _mapVal.end()) {
        if (it->first == INT32_0) {
            result = FALSE;
        }
        /* A5-1-1 http://www.cplusplus.com/reference/vector/vector/begin/ */
        it++;
    }
    return result;
}

void sample_func_4(std::vector<UINT8> const & _dataInBytes) noexcept {
    std::vector<UINT8> oriData {65U,66U,67U,68U};
    /* A23-0-1 http://www.cplusplus.com/reference/vector/vector/insert/ */
    oriData.insert(oriData.end(), _dataInBytes.cbegin(), _dataInBytes.cend());

    std::vector<UINT8>::const_iterator const pos { _dataInBytes.begin() };
    std::string result { std::string(pos, pos + static_cast<INT64>(_dataInBytes.size())) };

    static_cast<void>(std::endl(std::cout << "sample_func_4: " << result));
}

void use_datatype1(DataType1 const & _d)
{
    static_cast<void>(std::endl(std::cout << sizeof(_d)));
}

void use_datatype2(DataType2 const & _d)
{
    static_cast<void>(std::endl(std::cout << sizeof(_d)));
}

void use_datatype3(DataType3 const & _d)
{
    static_cast<void>(std::endl(std::cout << sizeof(_d)));
}

}

int main(int argc, char * argv[]) {
    using namespace SAMPLE_CODE;
    bool result { true };

    std::endl(std::cout << "Hello World!");

    std::map<INT32, std::string> mymap {};
    mymap[INT32_0] = "INT32_0";

    use_datatype1(DataType1());
    use_datatype2(DataType2());
    use_datatype3(DataType3());

    result = sample_func_1(1605509735);
    result = sample_func_1(1605509800);
    sample_func_2("sample_func_3");
    result = sample_func_3(mymap);
    
    std::vector<UINT8> dataInBytes {69U,70U,71U,72U};
    sample_func_4(dataInBytes);

    std::shared_ptr<DataS1> data1 { std::make_shared<DataS1>() };
    std::shared_ptr<DataS2> data2 { std::make_shared<DataS2>() };
    static constexpr UINT32 CNT_2 {2U};
    SampleClass1 sc1(data1, data2, CNT_2);
    sc1.Start();

    std::endl(std::cout << "MAIN exit");
    
    if (result) {
        return EXIT_SUCCESS;
    } else {
        return EXIT_FAILURE;
    }
}

